

#include "unity.h"
#include "parse_Rxpacket.h"
#include "mock_eth_commom.h"


// Global variables that need to be accessible
extern u32 busService;
extern struct Eth_status_cnt Eth_status;

void setUp(void) {
    // Reset global variables before each test
    busService = 0;
    Eth_status.update_expect_cnt = 0;
    Eth_status.update_status = 0;
}

void tearDown(void) {
    // Clean up after each test
}

// Test case 1: Non-IPv6 packet
void test_parse_Rxpacket_ShouldReturnMinusOne_WhenFrameIsNotIPv6(void) {
    EthernetFrame frame;
    struct eth_header* eth_hdr = (struct eth_header*)&frame;
    
    // Set non-IPv6 ether type
    eth_hdr->ether_type = 0x0800; // IPv4
    
    int result = parse_Rxpacket(&frame);
    
    TEST_ASSERT_EQUAL(-1, result);
}

// Test case 2: IPv6 ICMPv6 packet processing
void test_parse_Rxpacket_ShouldProcessICMPv6Packet_WhenFrameIsIPv6AndICMPv6(void) {
    EthernetFrame frame;
    memset(&frame, 0, sizeof(EthernetFrame));
    
    struct eth_header* eth_hdr = (struct eth_header*)&frame;
    struct ipv6_header* ip6_hdr = (struct ipv6_header*)((char*)&frame + IPV6_HEADER_LOC);
    struct icmpv6_msg* icmp6_rx = (struct icmpv6_msg*)((char*)&frame + ICMP_HEADER_LOC);
    
    // Set IPv6 ether type
    eth_hdr->ether_type = 0xDD86;
    ip6_hdr->next_header = ICMPV6_PROTOCOL;
    
    // Set up ICMPv6 data
    icmp6_rx->identifier = 0x1234;
    icmp6_rx->sequence = 0x5678;
    memcpy(icmp6_rx->icmpv6_data, "Hello ICMPv6", 12);
    
    // Set source MAC and IP
    memcpy(eth_hdr->src_mac, "\x01\x02\x03\x04\x05\x06", XAE_MAC_ADDR_SIZE);
    memcpy(ip6_hdr->src_ipaddr, "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16);
    
    // Mock expectations
    eth_ICMPv6Frame_init_ExpectAnyArgs();
    transLayer_checksum_ExpectAnyArgsAndReturn(0xABCD);

    Xil_Htons_ExpectAndReturn(0xABCD, 0xCDAB);
    eth_FifoTransData_ExpectAnyArgsAndReturn(0xABCD);
    B1553_TMadd_Comm_Eth_TX_Count_ExpectAnyArgs();
    
    int result = parse_Rxpacket(&frame);
    
    TEST_ASSERT_EQUAL(0, result);
}

// Test case 3: IPv6 UDP packet with port < 50000
void test_parse_Rxpacket_ShouldReturnMinusOne_WhenUDPPortIsLessThan50000(void) {
    EthernetFrame frame;
    memset(&frame, 0, sizeof(EthernetFrame));
    
    struct eth_header* eth_hdr = (struct eth_header*)&frame;
    struct ipv6_header* ip6_hdr = (struct ipv6_header*)((char*)&frame + IPV6_HEADER_LOC);
    struct udp_header* udp_hdr = (struct udp_header*)((char*)&frame + UDP_HEADER_LOC);
    
    // Set IPv6 ether type and UDP protocol
    eth_hdr->ether_type = 0xDD86;
    ip6_hdr->next_header = UDP_PROTOCOL;
    
    // Set UDP port < 50000
    udp_hdr->dst_port = 49999;
    
    Xil_Htons_ExpectAndReturn(49999, 49999);
    
    int result = parse_Rxpacket(&frame);
    
    TEST_ASSERT_EQUAL(-1, result);
}

// Test case 4: IPv6 UDP packet with wrong data type
void test_parse_Rxpacket_ShouldReturnMinusOne_WhenAppDataTypeIsWrong(void) {
    EthernetFrame frame;
    memset(&frame, 0, sizeof(EthernetFrame));
    
    struct eth_header* eth_hdr = (struct eth_header*)&frame;
    struct ipv6_header* ip6_hdr = (struct ipv6_header*)((char*)&frame + IPV6_HEADER_LOC);
    struct udp_header* udp_hdr = (struct udp_header*)((char*)&frame + UDP_HEADER_LOC);
    struct app_header* app_hdr = (struct app_header*)((char*)&frame + APP_HEADER_LOC);
    
    // Set IPv6 ether type and UDP protocol
    eth_hdr->ether_type = 0xDD86;
    ip6_hdr->next_header = UDP_PROTOCOL;
    
    // Set UDP port >= 50000
    udp_hdr->dst_port = 50000;
    
    // Set wrong data type
    app_hdr->data_type = 0x02; // Wrong type
    app_hdr->port = 0x29;      // Correct port
    
    Xil_Htons_ExpectAndReturn(50000, 50000);
    B1553_TMadd_Comm_Update_Error_Count_ExpectAnyArgs();
    B1553_TMset_Update_stat_ExpectAnyArgs();
    
    int result = parse_Rxpacket(&frame);
    
    TEST_ASSERT_EQUAL(-1, result);
}

// Test case 5: IPv6 UDP packet with wrong port
void test_parse_Rxpacket_ShouldReturnMinusOne_WhenAppPortIsWrong(void) {
    EthernetFrame frame;
    memset(&frame, 0, sizeof(EthernetFrame));
    
    struct eth_header* eth_hdr = (struct eth_header*)&frame;
    struct ipv6_header* ip6_hdr = (struct ipv6_header*)((char*)&frame + IPV6_HEADER_LOC);
    struct udp_header* udp_hdr = (struct udp_header*)((char*)&frame + UDP_HEADER_LOC);
    struct app_header* app_hdr = (struct app_header*)((char*)&frame + APP_HEADER_LOC);
    
    // Set IPv6 ether type and UDP protocol
    eth_hdr->ether_type = 0xDD86;
    ip6_hdr->next_header = UDP_PROTOCOL;
    
    // Set UDP port >= 50000
    udp_hdr->dst_port = 50000;
    
    // Set correct data type but wrong port
    app_hdr->data_type = 0x01; // Correct type
    app_hdr->port = 0x30;      // Wrong port
    
    Xil_Htons_ExpectAndReturn(50000, 50000);
    B1553_TMadd_Comm_Update_Error_Count_ExpectAnyArgs();
    B1553_TMset_Update_stat_ExpectAnyArgs();
    
    int result = parse_Rxpacket(&frame);
    
    TEST_ASSERT_EQUAL(-1, result);
}

// Test case 6: IPv6 UDP packet with correct data but not finished updating
void test_parse_Rxpacket_ShouldProcessCorrectUDPData_WhenUpdateNotFinished(void) {
    EthernetFrame frame;
    memset(&frame, 0, sizeof(EthernetFrame));
    
    struct eth_header* eth_hdr = (struct eth_header*)&frame;
    struct ipv6_header* ip6_hdr = (struct ipv6_header*)((char*)&frame + IPV6_HEADER_LOC);
    struct udp_header* udp_hdr = (struct udp_header*)((char*)&frame + UDP_HEADER_LOC);
    struct app_header* app_hdr = (struct app_header*)((char*)&frame + APP_HEADER_LOC);
    struct app_vcdu_prog* vcdu_prog = (struct app_vcdu_prog*)((char*)&frame + APP_VCDU_DATA_LOC);
    
    // Set IPv6 ether type and UDP protocol
    eth_hdr->ether_type = 0xDD86;
    ip6_hdr->next_header = UDP_PROTOCOL;
    
    // Set UDP port >= 50000
    udp_hdr->dst_port = 50000;
    
    // Set correct data type and port
    app_hdr->data_type = 0x01;
    app_hdr->port = 0x29;
    
    // Fill some data in bitstream
    memset(vcdu_prog->bit_stream_data, 0xAA, 100);
    
    Xil_Htons_ExpectAndReturn(50000, 50000);
    uart_rs01_send_ExpectAnyArgs();
    B1553_TMadd_Comm_Update_Count_ExpectAnyArgs();
    B1553_TMset_Update_stat_ExpectAnyArgs();
    
    int result = parse_Rxpacket(&frame);
    
    TEST_ASSERT_EQUAL(0, result);
    TEST_ASSERT_EQUAL(1, Eth_status.update_expect_cnt);
    TEST_ASSERT_EQUAL(PROGRAM_UPDATING, Eth_status.update_status);
}

// Test case 7: IPv6 UDP packet with correct data and finished updating
void test_parse_Rxpacket_ShouldProcessCorrectUDPData_WhenUpdateFinished(void) {
    EthernetFrame frame;
    memset(&frame, 0, sizeof(EthernetFrame));
    
    struct eth_header* eth_hdr = (struct eth_header*)&frame;
    struct ipv6_header* ip6_hdr = (struct ipv6_header*)((char*)&frame + IPV6_HEADER_LOC);
    struct udp_header* udp_hdr = (struct udp_header*)((char*)&frame + UDP_HEADER_LOC);
    struct app_header* app_hdr = (struct app_header*)((char*)&frame + APP_HEADER_LOC);
    struct app_vcdu_prog* vcdu_prog = (struct app_vcdu_prog*)((char*)&frame + APP_VCDU_DATA_LOC);
    
    // Set IPv6 ether type and UDP protocol
    eth_hdr->ether_type = 0xDD86;
    ip6_hdr->next_header = UDP_PROTOCOL;
    
    // Set UDP port >= 50000
    udp_hdr->dst_port = 50000;
    
    // Set correct data type and port
    app_hdr->data_type = 0x01;
    app_hdr->port = 0x29;
    
    // Fill some data in bitstream
    memset(vcdu_prog->bit_stream_data, 0xBB, 100);
    
    // Set counter to trigger finish condition
    Eth_status.update_expect_cnt = 255;
    
    Xil_Htons_ExpectAndReturn(50000, 50000);
    uart_rs01_send_ExpectAnyArgs();
    B1553_TMadd_Comm_Update_Count_ExpectAnyArgs();

    B1553_TMset_Update_stat_ExpectAnyArgs();
    uart_rs01_sendTM_Expect();
    uart_rs01_rcvTM_Expect();
    
    int result = parse_Rxpacket(&frame);
    
    TEST_ASSERT_EQUAL(0, result);
    TEST_ASSERT_EQUAL(256, Eth_status.update_expect_cnt);
    TEST_ASSERT_EQUAL(PROGRAM_UPDATE_DONE, Eth_status.update_status);
}

// Test case 8: IPv6 with other protocol
void test_parse_Rxpacket_ShouldReturnZero_WhenIPv6WithOtherProtocol(void) {
    EthernetFrame frame;
    memset(&frame, 0, sizeof(EthernetFrame));
    
    struct eth_header* eth_hdr = (struct eth_header*)&frame;
    struct ipv6_header* ip6_hdr = (struct ipv6_header*)((char*)&frame + IPV6_HEADER_LOC);
    
    // Set IPv6 ether type and other protocol
    eth_hdr->ether_type = 0xDD86;
    ip6_hdr->next_header = 6; // TCP protocol
    
    int result = parse_Rxpacket(&frame);
    
    TEST_ASSERT_EQUAL(-1, result);
}